package cn.wx.scholar.neo4j.service;

import java.lang.reflect.ParameterizedType;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.neo4j.ogm.model.Result;
import org.neo4j.ogm.session.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

public abstract class Neo4jBaseService <T> {

	@Autowired
	private Session session;
	
	/**
	 * 初步分页
	 * @return
	 * 
	 * 		//ORDER BY p.`h-index` DESC SKIP {sdnSkip} LIMIT {sdnLimit}
		
		/*"{\r\n" + 
		"	\"min\": -1,\r\n" + 
		"	\"3\": {\r\n" + 
		"		\"sort\": null,\r\n" + 
		"		\"offset\": 0,\r\n" + 
		"		\"pageSize\": 10,\r\n" + 
		"		\"pageNumber\": 0\r\n" + 
		"	},\r\n" + 
		"	\"max\": 101,\r\n" + 
		"	\"sdnLimit\": 10,\r\n" + 
		"	\"name\": \"(?i).*Natural language processing.*\",\r\n" + 
		"	\"sdnSkip\": 0\r\n" + 
		"}"
	 */
	
	public Page<T> queryPage(String cypher,
			final String countCypher,
			Map<String,Object> params,
			Pageable pageable) {
		
		if(StringUtils.isBlank(countCypher)) {
			return null;
		}
		
		Result result = session.query(countCypher + " as count ", params);
		
		int totalnum = getTotalNum(result);
		
		if(pageable != null) {
			
			if(params == null) {
				params = new HashMap<>();
			}
			
			int pageNo = pageable.getPageNumber();
			int pageSize = pageable.getPageSize();
			
			params.put("sdnSkip", pageNo * pageSize);
			params.put("sdnLimit", pageSize);
			
			StringBuffer sb = new StringBuffer(cypher);
			Sort sort = pageable.getSort();
			if(sort != null) {
				sb.append(" order by ");
				sort.forEach((v)-> sb.append(v.getProperty()).append(" ").append(v.getDirection().name()));
			}
			sb.append(" SKIP {sdnSkip} LIMIT {sdnLimit} ");
			
			cypher = sb.toString();
			
		}

		List<T> tl = (List<T>) session.query(getTClass(),cypher,params);
		
		return new PageImpl<>(tl, pageable, totalnum);
	}
	
	
	public List<T> queryList(final String cypher,Map<String,Object> params) {
		if(params == null) {
			params = new HashMap<>();
		}
		List<T> tl = (List<T>) session.query(getTClass(),cypher,params);
		return tl;
	}
	
	public Result queryListResult(final String cypher,Map<String,Object> params) {
		if(params == null) {
			params = new HashMap<>();
		}
		return session.query(cypher,params);
	}
	
	
	public Integer queryCountResult(final String cypher,Map<String,Object> params) {
		if(params == null) {
			params = new HashMap<>();
		}
		
		Result result = session.query(cypher,params);
		return getTotalNum(result);
	}
	
	/**
	 * 解析总数
	 * @param result
	 * @return
	 */
	public static int getTotalNum(Result result){
        int totalnum = 0;
        if(result==null)return totalnum;
        Iterator<Map<String,Object>> its = result.iterator();
        while (its.hasNext()){
            Map<String,Object> ret =  its.next();
            if(ret!=null){
                Object nums = ret.getOrDefault("count",0);
                if( nums != null ){
                    totalnum = Integer.parseInt(nums.toString());
                    break;
                }
            }
        }
        return totalnum;
	}
	
	/**
	 * 获取结果集的整数
	 * @param result
	 * @param columName
	 * @return
	 */
	public static int getResultInt(Result result,String columName){
        int totalnum = 0;
        if(result==null)return totalnum;
        Iterator<Map<String,Object>> its = result.iterator();
        while (its.hasNext()){
            Map<String,Object> ret =  its.next();
            if(ret!=null){
                Object nums = ret.getOrDefault(columName,0);
                if( nums != null ){
                    totalnum = Integer.parseInt(nums.toString());
                    break;
                }
            }
        }
        return totalnum;
	}
	
	@SuppressWarnings("unchecked")
	public Class<T> getTClass()
    {
        Class<T> tClass = (Class<T>)((ParameterizedType)getClass().
        		getGenericSuperclass()).
        		getActualTypeArguments()[0];
        return tClass;
    }
	
}
